package com.xcity.game.activity2;

import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Activity;
import com.xcity.db.mapper.ActivityMapper;
import com.xcity.util.DBUtils;

import naga.x.App;
import naga.x.common.Updatable;
import naga.x.game.time.TimeUpdater;
import naga.x.service.Service;
import naga.x.service.ServiceException;

/**
 * 运营活动服务类，管理所有运营活动
 * @author yang.li
 *
 */
public class ActivityService2 implements Service, Updatable {
	
	private List<Activity> activities;
	private long lastUpdateTime;
	
	protected static final Logger LOG = LoggerFactory.getLogger(ActivityService2.class);
	
	@Override
	public void startup() throws ServiceException {
		List<Activity> list = DBUtils.findAll(ActivityMapper.class);
		activities = list != null ? new CopyOnWriteArrayList<Activity>(list) : new CopyOnWriteArrayList<Activity>();
		for (int i = 0, size = activities.size(); i < size; i++) {
			Activity activity = activities.get(i);
			activity.init();
		}
		App.getApp().getUpdater().add(this);
	}

	@Override
	public void shutdown() throws ServiceException {
		for (int i = 0; i < activities.size(); i++) {
			Activity activity = activities.get(i);
			try {
				activity.save();
			} catch (Exception e) {
				String msg = MessageFormat.format("[ACTIVITY SAVE ERR]ID[{0,number,#}]NAME[{1}]IMPL[{2}]CAUSE[SERVER SHUTDOWN]",
													activity.getUniqueId(), activity.getName(), activity.getImplClass());
				LOG.error(msg, e);
			}
		}
	}

	@Override
	public String getId() {
		return getClass().getName();
	}

	@Override
	public boolean update() {
		if (TimeUpdater.getInstance().now() - lastUpdateTime < 60000) {
			return true;
		}
		long now = lastUpdateTime = TimeUpdater.getInstance().now();
		for (int i = 0; i < activities.size(); i++) {
			Activity activity = activities.get(i);
			if (activity.isActive()) {
				// 检查已开启的活动是否到了关闭时间
				if (!enable(activity, now)) {
					try {
						activity.shutdown();
						LOG.info("[ACTIVITY SHUTDOWN]ID[{}]NAME[{}]", activity.getUniqueId(), activity.getName());
					} catch (Exception e) {
						LOG.error("[ACTIVITY SHUTDOWN ERR]ID[" + activity.getUniqueId() + "]NAME[" + activity.getName() + "]", e);
					}
				}
			} else {
				// 检查已关闭的活动是否到了开启时间
				if (enable(activity, now)) {
					try {
						activity.startup();
						LOG.info("[ACTIVITY STARTUP]ID[{}]NAME[{}]", activity.getUniqueId(), activity.getName());
					} catch (Exception e) {
						LOG.error("[ACTIVITY STARTUP ERR]ID[" + activity.getUniqueId() + "]NAME[" + activity.getName() + "]", e);
					}
				}
			}
			
			if (activity.isActive()) {
				activity.update();
			}
		}
		return true;
	}
	
	public void add(Activity activity, String cause) {
		DBUtils.save(activity, ActivityMapper.class);
		activity.init();
		activities.add(activity);
		LOG.info("[ACTIVITY ADD]ID[{}]NAME[{}]CAUSE[{}]", activity.getUniqueId(), activity.getName(), cause);
	}
	
	public Activity remove(int id, String cause) {
		for (int i = 0; i < activities.size(); i++) {
			Activity activity = activities.get(i);
			if (id == activity.getUniqueId()) {
				if (activity.isActive()) {
					try {
						activity.shutdown();
					} catch (Exception e) {
						LOG.error("[ACTIVITY SHUTDOWN ERR]ID[" + activity.getUniqueId() + "]NAME[" + activity.getName() + "]CAUSE[" + cause + "]", e);
					}
				}
				activities.remove(i);
				DBUtils.delete(id, ActivityMapper.class);
				LOG.info("[ACTIVITY REMOVE]ID[{}]NAME[{}]CAUSE[{}]", id, activity.getName(), cause);
				return activity;
			}
		}
		return null;
	}
	
	public void update(Activity activity, String cause) {
		Activity act = find(activity.getUniqueId());
		if (act == null) {
			add(activity, cause);
			return;
		}
		if (act != activity) { // 如果不是同一个对象，则先同步数据
			act.setName(activity.getName());
			act.setDesc(activity.getDesc());
			act.setBeginTime(activity.getBeginTime());
			act.setEndTime(activity.getEndTime());
			act.setImplClass(activity.getImplClass());
			act.setData(activity.getData());
			activity = act;
		}
		activity.setDirty();
		DBUtils.update(activity, ActivityMapper.class);
		LOG.info("[ACTIVITY UPDATE]ID[{}]NAME[{}]CAUSE[{}]", activity.getUniqueId(), activity.getName(), cause);
	}
	
	public Activity find(int id) {
		for (int i = 0; i < activities.size(); i++) {
			Activity activity = activities.get(i);
			if (id == activity.getUniqueId()) {
				return activity;
			}
		}
		return null;
	}
	
	public <T extends ActivityImpl> T findImpl(Class<T> implClass) {
		for (int i = 0; i < activities.size(); i++) {
			Activity activity = activities.get(i);
			if (implClass.isAssignableFrom(activity.getImpl().getClass())) {
				return (T) activity.getImpl();
			}
		}
		return null;
	}
	
	public Activity[] getActivities() {
		return activities.toArray(new Activity[activities.size()]);
	}

	private static boolean enable(Activity activity, long now) {
		Date beginTime = activity.getBeginTime();
		Date endTime = activity.getEndTime();
		return (beginTime == null || now >= beginTime.getTime()) && (endTime == null || now < endTime.getTime());
	}
	
}
